﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.RestrictedUsage.CSharp.Compiler;
using EnvDTE;
using Microsoft.RestrictedUsage.CSharp.Core;
using Microsoft.RestrictedUsage.CSharp.Syntax;
using Microsoft.RestrictedUsage.CSharp.Semantics;
using Microsoft.VisualStudio.CSharp.Services.Language.Interop;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.RestrictedUsage.CSharp.Extensions;
using System.Collections.ObjectModel;
using devtm.Documentation.Structure;
using devtm.Collections;
using System.Xml.Linq;
using System.Text.RegularExpressions;
using devtm.Documentation.HierarchyModel;


namespace devtm.Documentation.CSharpModel
{

    public static class HierarchyParser
    {

        /// <summary>
        /// Parses the specified project.
        /// </summary>
        /// <param name="project">The project.</param>
        /// <param name="source">The source.</param>
        /// <returns></returns>
        public static void Parse(Project project, string source, MemberStructure lst)
        {

            try
            {

                if ((project != null) && !HierarchyUtilities.IsMiscellaneousProject(project))
                {

                    Compilation compilation = CSharpTextSelection.LanguageModel.CreateCompiler(project).GetCompilation();

                    IList<CSharpType> oo = compilation.MainAssembly.Types;

                    //SourceFile file = compilation.SourceFiles[new FileName(source)];

                    //foreach (ParseTreeNode node in file.GetParseTree().SelectFileCodeItems())
                    //{
                    //    if (node is AttributeSectionNode)
                    //        continue;

                    //    CSharpType typeDeclaration = compilation.GetTypeFromTypeDeclaration(node);

                    //    if (typeDeclaration != null)
                    //        CreateType(typeDeclaration, lst);
                        
                    //}


                    return oo;
                }
            }
            catch
            {

            }

        }

     


        private static void CreateType(CSharpType type, MemberStructure lst)
        {

            NamespaceStructure nameSpace = SetAndCreateNamespace(type, lst);

            TypeStructure t = new TypeStructure(nameSpace, type.Name.Text);

            #region properties

            t.IsAbstract = type.IsAbstract;
            t.IsArray = type.IsArray;
            t.IsAnonymousType = type.IsAnonymousType;
            t.IsClass = type.IsClass;
            t.IsConstructed = type.IsConstructed;
            t.IsContravariant = type.IsContravariant;
            t.IsCovariant = type.IsCovariant;
            t.IsDelegate = type.IsDelegate;
            t.IsDynamic = type.IsDynamic;
            t.IsEnum = type.IsEnum;
            t.IsInterface = type.IsInterface;
            t.IsInternal = type.IsInternal;
            t.IsNested = type.IsNested;
            t.IsPointer = type.IsPointer;
            t.IsPredefinedType = type.IsPredefinedType;
            t.IsPrivate = type.IsPrivate;
            t.IsProtected = type.IsProtected;
            t.IsProtectedOrInternal = type.IsProtectedOrInternal;
            t.IsPublic = type.IsPublic;
            t.IsReferenceType = type.IsReferenceType;
            t.IsSealed = type.IsSealed;
            t.IsStatic = type.IsStatic;
            t.IsStruct = type.IsStruct;
            t.IsTypeParameter = type.IsTypeParameter;
            t.IsUnknown = type.IsUnknown;
            t.IsValueType = type.IsValueType;

            #endregion

            CreateInterface(type.BaseInterfaces, t);

            CreateAttribute(type.Attributes, t);

            if (type.BaseClass != null)
                t.BaseType = new MemberStructure(null, type.BaseClass.Name.Text, null);

            CreateMembers(type.Members, t);

            CreateNestedTypes(type.NestedTypes, t);

            foreach (SourceLocation item in type.SourceLocations)
            {
                Location l = new Location();
                l.File = item.FileName.Value;
                l.Ligne = item.Position.Line;
                l.Colonne = item.Position.Character;
                l.IsValid = item.Position.IsValid;
                t.Location = l;
            }

            CreateNestedTypes(type.NestedTypes, t);
            CreateTypeArguments(type.TypeArguments, t);
            CreateTypeContrains(type.TypeConstraints, t);
            CreateTypeParameterPosition(type.TypeParameterPosition, t);
            CreateTypeParameters(type.TypeParameters, t);

            if (t.UnderlyingType != null)
                t.UnderlyingType = new MemberStructure(null, type.UnderlyingType.Name.Text, null);
            
            //CreateDocumentation(type.XMLDocumentation, t);

            //t.ImageName = InitializeImg(type);

        }

        #region Others
        
       

        private static void CreateNestedTypes(IList<CSharpType> iList, TypeStructure t)
        {

        }

        private static void CreateAttribute(IList<CSharpCustomAttribute> iList, MemberStructure t)
        {

        }

        private static void CreateInterface(IList<CSharpType> iList, TypeStructure t)
        {

        }




        private static void CreateTypeParameters(IList<CSharpType> iList, MemberStructure t)
        {

        }

        private static void CreateTypeParameterPosition(int p, MemberStructure t)
        {

        }

        private static void CreateTypeContrains(IList<CSharpType> iList, MemberStructure t)
        {
        }

        private static void CreateTypeArguments(IList<CSharpType> iList, MemberStructure t)
        {

        }

        #endregion

        #region Members

        private static void CreateMembers(IList<CSharpMember> iList, TypeStructure t)
        {
            foreach (CSharpMember i in iList)
            {


                try
                {

                

                MemberStructure ret = null;


                if (i.IsMethod)
                    ret = CreateMethod(i, t);

                else if (i.IsEvent)
                    ret = CreateEvent(i, t);

                else if (i.IsField)
                    ret = CreateField(i, t);

                else if (i.IsOperator)
                    ret = CreateOperator(i, t);

                else if (i.IsProperty)
                    ret = CreateProperty(i, t);

                else if (i.IsEnumMember)
                    ret = CreateEnum(i, t);

                //else if (i.IsFixedSizeBuffer)
                //    ret = CreateFixedSizeBuffer(i, t);

                if (ret == null)
                    continue;


                if (i.IsPrivate)
                    ret.Accessibility = MemberVisibility.Private;
                else if (i.IsPublic)
                    ret.Accessibility = MemberVisibility.Public;
                else if (i.IsProtected)
                    ret.Accessibility = MemberVisibility.Protected;
                else if (i.IsProtectedOrInternal)
                    ret.Accessibility = MemberVisibility.InternalProtected;
                else if (i.IsInternal)
                    ret.Accessibility = MemberVisibility.Internal;

                /*
                if (i.FixedBufferSize )

                IsGetAccessor
                IsSetAccessor

                MetadataToken;                
                
                IList<CSharpType> TypeArguments;
                IList<CSharpType> TypeParameters;
                XMLDocInfo XMLDocumentation;
         
                IsPartialImplementation;
                IsPartialSignature;
                */

                foreach (SourceLocation item in i.SourceLocations)
                {
                    Location l = new Location();
                    l.File = item.FileName.Value;
                    l.Ligne = item.Position.Line;
                    l.Colonne = item.Position.Character;
                    l.IsValid = item.Position.IsValid;
                    t.Location = l;
                }

                CreateTypeArguments(i.TypeArguments, t);
                CreateTypeParameters(i.TypeParameters, t);

                //CreateDocumentation(i.XMLDocumentation, t);

               //i.SymbolicIdentifier.TypeIdentifier.
                //i.OperatorKind = OperatorKind.None


                //ret.ImageName = InitializeImg(i);

                }
                catch (Exception ex)
                {

                   
                }

                
            }
            
            
            // ajouter les parametres, la porte et le static sur la clef pour qu'elle soit unique
            // associer les methodes et les proprietes.

        }

        private static FieldStructure CreateEnum(CSharpMember i, TypeStructure t)
        {
            FieldStructure f = new FieldStructure(t, i.Name.Text);
            return f;
        }


        #region Methods


        private static MethodStructure CreateMethod(CSharpMember i, TypeStructure t)
        {

            MethodStructure m = new MethodStructure(t, i.Name.Text, BuildKeyMethod(i, t));

            if (i.IsConstructor)
                m.MemberType = "Constructor";

            else if (i.IsDestructor)
                m.MemberType = "Destructor";

            if (i.ReturnType != null)
                m.Type = new MemberStructure(null, (i.ReturnType.ElementType != null) ? i.ReturnType.ElementType.ToString() : string.Empty, null);

            if (i.Parameters != null)
                foreach (CSharpParameter item in i.Parameters.OrderBy(c => c.Position))
                    CreateParameter(item, m);

            m.IsExternal = i.IsExtern;

            m.IsAbstract = i.IsAbstract;
            m.IsIndexer = i.IsIndexer;
            m.IsNew = i.IsNew;
            m.IsOverride = i.IsOverride;

            m.IsFinal = i.IsSealed;
            m.IsStatic = i.IsStatic;
            m.IsVirtual = i.IsVirtual;

            return m;
        }

        private static string BuildKeyMethod(CSharpMember i, TypeStructure t)
        {

            return i.ToString();
            
            //string n = i.Name.Text; ;

            //if (t.ContainsKey(n))
            //{

            //}

            //return n;
        }

        private static void CreateParameter(CSharpParameter item, MethodStructure m)
        {
            ParameterStructure p = new ParameterStructure(m, item.Name.Text);

            p.Type = new MemberStructure(null, (item.Type.ElementType != null) ? item.Type.ElementType.ToString() : item.Type.ToString(), null);


            p.IsIn = !item.IsOut && !item.IsRef;
            p.IsOut = item.IsOut;
            p.IsThis = item.IsThis;
            p.IsParams = item.IsParams;

            if (item.DefaultValue == null)
                CreateDefaultValue(item.DefaultValue, p);

        }

        private static void CreateDefaultValue(CSharpDefaultParameterValue cSharpDefaultParameterValue, ParameterStructure p)
        {

            p.IsOptional = true;
        }

        #endregion


        private static FieldStructure CreateField(CSharpMember i, TypeStructure t)
        {

            // IsEnumMember

            FieldStructure f = new FieldStructure(t, i.Name.Text);

            f.IsIndexer = i.IsIndexer;
            f.IsStatic = i.IsStatic;
            f.IsReadonly = i.IsReadonly;
            f.IsConstant = i.IsConstant;
            f.IsVolatile = i.IsVolatile;

            return f;
        }


        private static PropertyStructure CreateProperty(CSharpMember i, TypeStructure t)
        {
            PropertyStructure p = new PropertyStructure(t, i.Name.Text);

            p.Type = new MemberStructure(null, i.ReturnType.ToString(), null);

            p.IsAbstract = i.IsAbstract;
            p.IsIndexer = i.IsIndexer;
            p.IsNew = i.IsNew;
            p.IsOverride = i.IsOverride;

            p.IsFinal = i.IsSealed;
            p.IsStatic = i.IsStatic;
            p.IsVirtual = i.IsVirtual;

            return p;
        }

        private static EventStructure CreateEvent(CSharpMember i, TypeStructure t)
        {
            EventStructure e = new EventStructure(t, i.Name.Text);

            // IsAddAccessor 
            // IsRemoveAccessor 

            return e;
        }


        private static OperatorStructure CreateOperator(CSharpMember i, TypeStructure t)
        {
            OperatorStructure o = new OperatorStructure(t, i.Name.Text);

            o.Type = new MemberStructure(null, i.ReturnType.ToString(), null);

            return o;
        }

        private static void CreateFixedSizeBuffer(CSharpMember i, TypeStructure t)
        {
            throw new NotImplementedException();
        }

      
        #endregion

        #region Add namespace

        private static NamespaceStructure SetAndCreateNamespace(CSharpType type, MemberStructure lst)
        {


            MemberStructure ret = SetAndCreateNamespace(type.ContainingNamespace, lst);

            string n = type.ContainingNamespace.Name.Text;

            if (!ret.ContainsKey(n))
                return (NamespaceStructure)ret.Add(new NamespaceStructure(ret, n));

            return (NamespaceStructure)ret[n];
        }

        private static MemberStructure SetAndCreateNamespace(CSharpNamespace type, MemberStructure lst)
        {

            MemberStructure ret = null;

            if (type.ContainingNamespace != null)
                ret = SetAndCreateNamespace(type.ContainingNamespace, lst);
            else
                return null;

            string n = type.ContainingNamespace.Name.Text;

            if (string.IsNullOrEmpty(n))
                return lst;

            MemberStructure list = ret ?? lst;
            
            if (!list.ContainsKey(n))                       
                return new NamespaceStructure(ret, n);            
            else
                return list[n];

        }

        #endregion


        #region Image

        //private static string InitializeImg(CSharpType t)
        //{


        //    //if (t.IsStatic )

        //    if (t.IsStruct)
        //        return "Structure.gif";

        //    else if (t.IsInterface)
        //        return "Interface.gif";

        //    else if (t.IsEnum)
        //        return "Enumeration.gif";

        //    else if (t.IsDelegate)
        //        return "Delegate.gif";

        //    return "class.gif";





        //    /*
        //        if (t.IsInternal)
        //            return "class.gif";

        //        else if (t.IsPrivate)
        //            return "class.gif";

        //        else if (t.IsProtected)
        //            return "class.gif";

        //        else if (t.IsProtectedOrInternal)
        //            return "class.gif";
        //     */
        //}



        //private static string InitializeImg(CSharpMember i)
        //{


        //    string ret = "";

        //    if (i.IsPrivate)
        //        ret += "private";            
        //    else if (i.IsProtected)
        //        ret += "protected";
        //    else if (i.IsProtectedOrInternal)
        //        ret += "protected internal";
        //    else if (i.IsInternal)
        //        ret += "internal";
        //    else
        //        ret += "public";

            
        //    if (i.IsEvent)
        //        ret += "Event.gif";
        //    else if (i.IsField || i.IsEnumMember)
        //        ret += "Field.gif";
        //    else if (i.IsOperator)
        //        ret += "Operator.gif";
        //    else if (i.IsProperty)
        //        ret += "Property.gif";
        //    else
        //        ret += "Method.gif";

        //    return ret;
        //}

        #endregion

    }

}
